package gps

import (
	"math"
)

const earthRadius float64 = 6378.137

//Rad 角度转换为弧度
func Rad(d float64) float64 {
	return d * math.Pi / 180.0
}

//Distance 计算两点经纬度距离
func Distance(lon1, lat1, lon2, lat2 float64) float64 {
	radLat1 := Rad(lat1)
	radLat2 := Rad(lat2)
	a := radLat1 - radLat2
	b := Rad(lon1) - Rad(lon2)
	s := 2 * math.Asin(math.Sqrt(math.Pow(math.Sin(a/2), 2)+math.Cos(radLat1)*math.Cos(radLat2)*math.Pow(math.Sin(b/2), 2)))
	s = s * earthRadius
	s = s * 1000
	return s
}

//GetPoint 根据方位角和距离计算经纬度
func GetPoint(lon1 float64, lat1 float64, azimuth float64, r float64) (lon, lat float64) {
	const ARC = 6371393
	radLat1 := Rad(lat1)
	radAlpha := Rad(azimuth)

	lon2 := lon1 + r*math.Sin(radAlpha)/(ARC*math.Cos(radLat1)*2*math.Pi/360)
	lat2 := lat1 + r*math.Cos(radAlpha)/(ARC*2*math.Pi/360)
	return lon2, lat2
}

//计算一个点(x,y)是否在多边形内部，是的话返回true,否的话返回false
//采用PNPOLY算法，从该点引一条射线，如果与多边形相交点为奇数，则该点在内部，为偶数，则该点在外部
func pnpoly(nvert int, vertx []float64, verty []float64, testx, testy float64) bool {

	var c bool = false
	for i, j := 0, nvert-1; i < nvert; i, j = i+1, i {

		if ((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j]-vertx[i])*(testy-verty[i])/(verty[j]-verty[i])+vertx[i]) {
			c = !c
		}
	}
	return c
}

//Point 含经纬度坐标的点
type Point struct {
	Lon float64
	Lat float64
}

//PointIsInBorder 计算某点point(lon,lat)是否在多边形内部，polygon 表示多边形的点数组
func PointIsInBorder(point Point, polygon []Point) bool {
	nvert := len(polygon)
	vertx := make([]float64, nvert)
	verty := make([]float64, nvert)
	for i := range polygon {
		vertx[i] = polygon[i].Lon
		verty[i] = polygon[i].Lat
	}

	return pnpoly(nvert, vertx, verty, point.Lon, point.Lat)
}
